/**
 * 
 */
package edu.hsbremen.teamscore.ui;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import edu.hsbremen.teamscore.R;
import edu.hsbremen.teamscore.events.TimerObserver;

/**
 * Custom UiElement für die @see android.os.CountDownTimer Klasse.
 * 
 * @author basster
 * 
 */
public class UiCountdownTimer extends View {

	private Paint _mTextPaint;
	private String _mText;
	private int _mAscent;

	private CountDownTimer _timer;
	private long _millisInTheFuture = 0;
	
	private long _millisUntilFinished = 0;
	
	private List<TimerObserver> _events = new ArrayList<TimerObserver>();
	
	/**
	 * @param context
	 */
	public UiCountdownTimer(Context context) {
		super(context);
		initLabelView();
	}

	/**
	 * Construct object, initializing with any attributes we understand from a
	 * layout file. These attributes are defined in
	 * SDK/assets/res/any/classes.xml.
	 * 
	 * @see android.view.View#View(android.content.Context,
	 *      android.util.AttributeSet)
	 */
	public UiCountdownTimer(Context context, AttributeSet attrs) {
		super(context, attrs);
		initLabelView();

		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.UiCountdownTimer);

		// Retrieve the color(s) to be used for this view and apply them.
		// Note, if you only care about supporting a single color, that you
		// can instead call a.getColor() and pass that to setTextColor().
		setTextColor(a.getColor(R.styleable.UiCountdownTimer_textColor,
				0xFF000000));

		int textSize = a.getDimensionPixelOffset(
				R.styleable.UiCountdownTimer_textSize, 0);
		if (textSize > 0) {
			setTextSize(textSize);
		}

		int minutes = a.getInteger(R.styleable.UiCountdownTimer_seconds, 5);
		this.setMillisInTheFuture(minutes * 1000);

		a.recycle();

		initTimer(this._millisInTheFuture);
	}

	private void initTimer(long millis) {
		setText(formatTime(millis));
		
		_timer = null;
		
		_timer = new CountDownTimer(millis, 1) {

			@Override
			public void onTick(long millisUntilFinished) {
				// Log.d(UiCountdownTimer.class.getSimpleName(), "Tick: " + String.valueOf(millisUntilFinished));
				UiCountdownTimer.this._millisUntilFinished = millisUntilFinished;
				
				// UI nur alle 500 ms aktualisieren
				// unter einer Minute 30 mal die Sek. aktualisieren.
				if (millisUntilFinished % 500 == 0 ||
						(millisUntilFinished <= 60000 && millisUntilFinished % (1000 / 30) == 0)
						)
					setText(formatTime(millisUntilFinished));
				
				notifyTimerEvents(millisUntilFinished);
			}

			@Override
			public void onFinish() {
				Log.d(UiCountdownTimer.class.getSimpleName(),
						"Countdown finished!");
				setText("00:00");
				this.cancel();
			}
		};
	}
	
	private final void initLabelView() {
				
		_mTextPaint = new Paint();
		_mTextPaint.setAntiAlias(true);
		// Must manually scale the desired text size to match screen density
		_mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
		_mTextPaint.setColor(0xFF000000);
		setPadding(3, 3, 3, 3);
	}

	public void setMillisInTheFuture(int millis) {
		this._millisInTheFuture = millis;
	}
	
	private void notifyTimerEvents(long millisUntilFinished) {
		for (TimerObserver evt: _events) {
			if (evt.getMillisWhenShouldHappen() >= millisUntilFinished) {
				evt.update();
				_events.remove(evt);
			}
		}		
	}
	
	public void addTimerEvent(TimerObserver to) {
		_events.add(to);
	}
	
	public void removeTimerEvent(TimerObserver to) {
		_events.remove(to);
	}
	

	private String formatTime(long millis) {
		
		long seconds = millis / 1000;
		long minutes = seconds / 60;
		int tenth = 0;
		
		String result = leadingZero((int)minutes) + ":" + leadingZero((int)(seconds % 60));
		
		if (minutes == 0) {
			tenth = (int)(millis % 100);
			result = leadingZero((int)seconds) + ":" + leadingZero(tenth);
		}

		return result;
	}

	private String leadingZero(int num) {
		if (num < 10)
			return "0" + num;
		else
			return String.valueOf(num);
	}

	public void startCountdown() {	
		Log.d(UiCountdownTimer.class.getSimpleName(), "Start Countdown");
				
		initTimer(this._millisUntilFinished == 0 ? this._millisInTheFuture : this._millisUntilFinished);
		_timer.start();
	}

	public void stopCountdown() {
		Log.d(UiCountdownTimer.class.getSimpleName(), "Stop Countdown");
		_timer.cancel();
	}
	
	public void resetCountdown() {
		Log.d(UiCountdownTimer.class.getSimpleName(), "Reset Countdown");
		_timer.cancel();
		_millisUntilFinished = 0;
		setText(formatTime(_millisInTheFuture));
	}
	
	public String getCurrent(){
		return _mText;
	}

	/**
	 * Sets the text to display in this label
	 * 
	 * @param text
	 *            The text to display. This will be drawn as one line.
	 */
	public void setText(String text) {
		_mText = text;
		requestLayout();
		invalidate();
	}

	/**
	 * Sets the text size for this label
	 * 
	 * @param size
	 *            Font size
	 */
	public void setTextSize(int size) {
		// This text size has been pre-scaled by the getDimensionPixelOffset
		// method
		_mTextPaint.setTextSize(size);
		requestLayout();
		invalidate();
	}

	/**
	 * Sets the text color for this label.
	 * 
	 * @param color
	 *            ARGB value for the text
	 */
	public void setTextColor(int color) {
		_mTextPaint.setColor(color);
		invalidate();
	}

	/**
	 * @see android.view.View#measure(int, int)
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(measureWidth(widthMeasureSpec),
				measureHeight(heightMeasureSpec));
	}

	/**
	 * Determines the width of this view
	 * 
	 * @param measureSpec
	 *            A measureSpec packed into an int
	 * @return The width of the view, honoring constraints from measureSpec
	 */
	private int measureWidth(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		if (specMode == MeasureSpec.EXACTLY) {
			// We were told how big to be
			result = specSize;
		} else {
			// Measure the text
			result = (int) _mTextPaint.measureText(_mText) + getPaddingLeft()
					+ getPaddingRight();
			if (specMode == MeasureSpec.AT_MOST) {
				// Respect AT_MOST value if that was what is called for by
				// measureSpec
				result = Math.min(result, specSize);
			}
		}

		return result;
	}

	/**
	 * Determines the height of this view
	 * 
	 * @param measureSpec
	 *            A measureSpec packed into an int
	 * @return The height of the view, honoring constraints from measureSpec
	 */
	private int measureHeight(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		_mAscent = (int) _mTextPaint.ascent();
		if (specMode == MeasureSpec.EXACTLY) {
			// We were told how big to be
			result = specSize;
		} else {
			// Measure the text (beware: ascent is a negative number)
			result = (int) (-_mAscent + _mTextPaint.descent()) + getPaddingTop()
					+ getPaddingBottom();
			if (specMode == MeasureSpec.AT_MOST) {
				// Respect AT_MOST value if that was what is called for by
				// measureSpec
				result = Math.min(result, specSize);
			}
		}
		return result;
	}

	/**
	 * Render the text
	 * 
	 * @see android.view.View#onDraw(android.graphics.Canvas)
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawText(_mText, getPaddingLeft(), getPaddingTop() - _mAscent,
				_mTextPaint);
	}
}
